﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Globalization;
using System.Reflection;

using Ict.DataAccess.Attributes;

namespace Ict.DataAccess
{
    public class DmlEncoder
    {

        /// <summary>
        /// 根据数据类的属性（及其属性上的标记特性）获得字段名称
        /// </summary>
        /// <param name="info">属性的详细信息</param>
        /// <param name="isReadonly">是否为只读</param>
        /// <returns>字段名称</returns>
        public virtual string ExtractFieldName(PropertyInfo info, ref bool isReadonly)
        {
            object[] attrs = info.GetCustomAttributes(true);

            string fieldName = info.Name;

            foreach (object attr in attrs)
            {
                if (attr is FieldAttribute)
                {
                    fieldName = ((FieldAttribute)attr).FieldName;
                }
                else if (attr is ReadonlyFieldAttribute || attr is IdentityFieldAttribute)
                {
                    isReadonly = true;
                }
                else if (attr is NonFieldAttribute)
                {
                    fieldName = null;
                    break;
                }
            }
            return fieldName;
        }

        /// <summary>
        /// 将对象指转成SQL的字符串
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public virtual string EncodeValue(object value)
        {
            if (value == null)
                return "NULL";
            Type t = value.GetType();
            string valueStr = "";
            if (t == typeof(string))
                valueStr = EncodeString(value as string, true);
            else if (t == typeof(DateTime))
                valueStr = EncodeDateTime((DateTime)value);
            else if (t == typeof(bool))
            {
                valueStr = (bool)value ? "1" : "0";
            }
            else if (t == typeof(DBNull))
                valueStr = "NULL";
            else if (t == typeof(Guid))
                valueStr = "'" + ((Guid)value).ToString() + "'";
            else if (t.IsEnum)
            {
                valueStr = ((int)value).ToString();
            }
            else
                valueStr = value.ToString();
            if (valueStr == "''")
                return "NULL";
            return valueStr;
        }

        public virtual string EncodeString(string fieldValue, bool quote)
        {
            fieldValue = fieldValue.Replace("'", "''");
            if (quote)
                fieldValue = "'" + fieldValue + "'";
            return fieldValue;
        }

        public virtual string EncodeDateTime(DateTime dateTime)
        {
            return "'" + dateTime.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture) + "'";
        }

        public virtual string EncodeLogicalOperator(ExpressionType expressionType)
        {
            switch (expressionType)
            {
                case ExpressionType.AndAlso:
                    return "AND";
                case ExpressionType.Not:
                    return "NOT";
                case ExpressionType.OrElse:
                    return "OR";
                default:
                    throw new NotSupportedException(string.Format("不支持的逻辑运算符: {0}", expressionType.ToString()));
            }
        }

        public virtual string EncodeOperator(ExpressionType expressionType, Type type, 
            bool bNullValue, out bool isFunction)
        {
            isFunction = false;
            switch (expressionType)
            {
                case ExpressionType.Equal:
                    if (bNullValue)
                        return "IS";
                    return "=";
                case ExpressionType.GreaterThan:
                    return ">";
                case ExpressionType.LessThan:
                    return "<";
                case ExpressionType.NotEqual:
                    if (bNullValue)
                        return "IS NOT";
                    return "<>";
                case ExpressionType.GreaterThanOrEqual:
                    return ">=";
                case ExpressionType.LessThanOrEqual:
                    return "<=";

                case ExpressionType.Add:
                    return "+";
                case ExpressionType.Subtract:
                    return "-";
                case ExpressionType.Multiply:
                    return "*";
                case ExpressionType.Divide:
                    return "/";
                case ExpressionType.And:
                    return "&";
                case ExpressionType.Or:
                    return "|";
                case ExpressionType.ExclusiveOr:
                    return "^";
                case ExpressionType.Coalesce:
                    isFunction = true;
                    return "ISNULL";
                default:
                    throw new NotSupportedException(string.Format("不支持的运算符: {0}", expressionType.ToString()));
            }
        }

        /// <summary>
        /// 将表达式编码成SQL形式的字符串
        /// </summary>
        /// <param name="expressionType"></param>
        /// <param name="operandType"></param>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        public virtual string EncodeExpression(ExpressionType expressionType, Type operandType, 
            string left, string right)
        {
            bool isFunction;
            string op = EncodeOperator(expressionType, operandType,
                (left == "NULL" || right == "NULL"), out isFunction);

            if (isFunction)
            {
                return op + "(" + left + ", " + right + ")";
            }
            else
            {
                return left + " " + op + " " + right;
            }
        }
    }
}
